#include <string.h>
#include <stdlib.h>

typedef struct {
   char *filename;
   FILE *fi;
   int ncol;   
   int current_row;
} snps_data_t;


/* 
 * Create snp matrix data file 
 * @param ncol The number of columns in the matrix file (input)
 * @return snps_data_t
 */
snps_data_t *new_snps(char* filename,int ncol) {
   char *line, *word;
   ssize_t len;
   size_t bufsize;
   int col;
   snps_data_t *snps_data;

   snps_data = (snps_data_t *) malloc(sizeof(snps_data_t));
   if ((snps_data->fi = fopen(filename,"r")) == NULL) {
      fprintf(stderr,"Cannot open file %s\n",filename);
      exit(1);
   }

   snps_data->filename = filename;

   // Determine the number of columns from the first line.
   line = NULL;
   if ((len = getline(&line,&bufsize,snps_data->fi)) < 0) {
      fprintf(stderr,"Cannot read a line in %s\n",filename);
      exit(1);
   }
   col = 0;
   while ((word = (char *) strtok(line,"\t \r\n")) != NULL) {
      col++;
      line = NULL;
   }
   if (col !=  ncol) {
      fprintf(stderr,"Number of columns mismatched\n");
      exit(1);
   }
   snps_data->ncol = ncol;
   snps_data->current_row = -1;

   rewind(snps_data->fi);
  
   return snps_data;
}


/*
 * Reset the file pointer
 * @param snps_data The snps_data_t object (input)
 */
void reset_snps(snps_data_t *snps_data) {
   rewind(snps_data->fi);
   snps_data->current_row = -1;
}

/*
 * Close the underlying file
 */
void close_snps(snps_data_t *snps_data) {
   fclose(snps_data->fi);
   snps_data->ncol = 0;
   snps_data->current_row = -1;
}

/* 
 * Read next rows from snps_data_t
 * @param snps_data The snps_data_t object (input)
 * @param nrow The number of rows to be read (input)
 * @param output The address of output buffer (input) 
 * @param size The maximum size of the output (input)
 * @return The number of rows actually read; 0 indicate EOF; otherwise error
 */
/*
int read_next_snps(snps_data_t *snps_data,int nrow,float *output,int size) {
   int i,j;

   int real_size = nrow*(snps_data->ncol)*sizeof(float); 
   if (real_size > size) {
      fprintf(stderr,"Output buffer is too small\n");
      exit(1);
   }
   for (i=0; i < nrow; i++) {
      for (j=0; j < snps_data->ncol; j++) {
         if (fscanf(snps_data->fi,"%f",&output[i*snps_data->ncol + j]) != 1) {
            break;                       
         }
      }
      if (feof(snps_data->fi) || ferror(snps_data->fi)) {
         break;
      }
   }

   if (ferror(snps_data->fi)) {
      return -1;
   } else {
      snps_data->current_row += i;
      return i;
   }

}
*/
int read_next_snps(snps_data_t *snps_data,int nrow,float *output,int size) {
   int i,j;

   int real_size = nrow*(snps_data->ncol)*sizeof(float); 
   if (real_size > size) {
      fprintf(stderr,"Output buffer is too small\n");
      exit(1);
   }

   char *line,*word,*str;
   size_t bufsize;
   ssize_t len;

   line = NULL;
   i = 0;
   while ( (i < nrow) && ((len = getline(&line,&bufsize,snps_data->fi)) >= 0) ) {
      str = line;
      for (j=0; j < snps_data->ncol; j++) {
         if ((word = (char *) strtok(str,"\t \r\n")) == NULL) {
            fprintf(stderr,"File %s has not enough columns in row %d\n",snps_data->filename,snps_data->current_row+1);
            exit(1);
         }
         output[i*snps_data->ncol + j] = atof(word);
         str = NULL; 
      }
      i++;
      snps_data->current_row++;
   }
   free(line); 

   if (ferror(snps_data->fi)) {
      return -1;
   } else {
      return i;
   }

}
